{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Programming Style\n",
    "\n",
    "**Time**\n",
    "- teaching: 10 min\n",
    "- exercises: 10 min (exploratory)\n",
    "\n",
    "**Questions**:\n",
    "- \"How can I make my programs more readable?\"\n",
    "- \"How do most programmers format their code?\"\n",
    "\n",
    "**Learning Objectives**:\n",
    "- \"Learn how to write code for others.\"\n",
    "- \"Explore the PEP 8 style guide.\"\n",
    "\n",
    "**keypoints**\n",
    "- \"Be clear with your code.\"\n",
    "- \"Write comments, even if it seems obvious to you (it won't tomorrow!).\"\n",
    "- \"Code with other users in mind.\"\n",
    "* * * * *\n",
    "\n",
    "## Good Python Code is Readable\n",
    "\n",
    "- If you ask Python programmers what they like most in Python, they will often say its high readability.\n",
    "- Indeed, a high level of readability is at the heart of the design of the Python language, following the recognised fact that code is read much more often than it is written.\n",
    "- How do you help readers of your code? "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Pythonic Way"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import this"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Docstrings and Comments\n",
    "\n",
    "Docstrings = **How to use** code\n",
    "\n",
    "Comments = **Why** (rationale) & **how** code works\n",
    "\n",
    "Both of these groups include **you**, so write good docstrings and comments!\n",
    "\n",
    "Comments explain why, and are for the maintainers of your code. Examples include notes to yourself, like: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# !!! BUG: ...\n",
    "\n",
    "# !!! FIX: This is a hack, refactor later\n",
    "\n",
    "# ??? Why is this here?\n",
    "\n",
    "# XXX This is where I stopped checking"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Docstrings explain how to use code, and are for the **users** of your code. Uses of docstrings:\n",
    "\n",
    "* Explain the purpose of the function even if it seems obvious to you, because it might not be obvious to someone else later on.\n",
    "* Describe the parameters expected, the return values, and any exceptions raised.\n",
    "* If the [method](https://github.com/dlab-berkeley/python-intensive/blob/master/Glossary.md#method) is tightly coupled with a single caller, make some mention of the caller (though be careful as the caller might change later)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def even_or_odd(x=0):\n",
    "    \"\"\"\n",
    "    \"Find whether a number x is even or odd.\n",
    "     >>> even_or_odd(10)\n",
    "     '10 is Even!'\n",
    "     >>> even_or_odd(5)\n",
    "     '5 is Odd!'\n",
    "\n",
    "     note that whenever a float is provided, then\n",
    "     the closest [integer](https://github.com/dlab-berkeley/python-intensive/blob/master/Glossary.md#integer) is used 22 >>> even_or_odd(3.2)\n",
    "     >>> even_or_odd(3.2)\n",
    "    '3 is Odd!'\n",
    "     in case of negative numbers, the positive is taken\n",
    "     >>> even_or_odd(-2) 28 '-2 is Even!'\n",
    "     \"\"\"\n",
    "    if x % 2 == 0:\n",
    "         return \"%d is Even!\" % x \n",
    "    return \"%d is Odd!\" % x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When using Python in interactive mode from the shell, you can use the help() function to see the docstring. In Jupyter, you can see it like so:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "?even_or_odd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "False comments & docstrings are worse than none at all. So keep them up to date! When you make changes, make sure the comments & docstrings are consistent with the code, and don't contradict it.\n",
    "\n",
    "There's an entire PEP about docstrings, PEP 257, \"Docstring Conventions\":\n",
    "\n",
    "http://www.python.org/dev/peps/pep-0257/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Long Lines & Continuations\n",
    "\n",
    "* Keep lines below 80 characters in length.\n",
    "\n",
    "* Use implied line continuation inside parentheses:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "my_very_big_string = (\n",
    "    \"For a long time I used to go to bed early. Sometimes, \"\n",
    "    \"when I had put out my candle, my eyes would close so quickly \"\n",
    "    \"that I had not even time to say “I’m going to sleep.”\"\n",
    ")\n",
    "\n",
    "from some.deep.module.inside.a.module import (\n",
    "    a_nice_function, another_nice_function, yet_another_nice_function)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or a backslash, although this is not as recommended:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "my_very_big_string = \"\"\"For a long time I used to go to bed early. Sometimes, \\\n",
    "    when I had put out my candle, my eyes would close so quickly that I had not even \\\n",
    "    time to say “I’m going to sleep.”\"\"\"\n",
    "\n",
    "from some.deep.module.inside.a.module import a_nice_function, another_nice_function, \\\n",
    "    yet_another_nice_function"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Naming Conventions\n",
    "\n",
    "\"The best programmer is the one who can come up with the best names\"\n",
    "\n",
    "* Good names replace comments and make code self-documenting\n",
    "* variables, functions, files, etc. should consist of complete words. Try to avoid abbreviations.\n",
    "* Use this principle in your coding: frequent=short; infrequent=long"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# bad code\n",
    "a = 1\n",
    "a = 'a string'\n",
    "def a():\n",
    "    pass  # Do something\n",
    "\n",
    "# good code\n",
    "count = 1\n",
    "msg = 'a string'\n",
    "def func():\n",
    "    pass  # Do something"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because of dynamic typing, it is better to use different names even for things that are related, when they have a different type:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# this is bad\n",
    "items = 'a b c d'  # This is a string...\n",
    "items = items.split(' ')  # ...becoming a list\n",
    "items = set(items)  # ...and then a set"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is no efficiency gain when reusing names: the assignments will have to create new objects anyway. However, when the complexity grows and each assignment is separated by other lines of code, including ‘if’ branches and loops, it becomes harder to ascertain what a given variable’s [type](https://github.com/dlab-berkeley/python-intensive/blob/master/Glossary.md#type) is."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here are some more style rules from PEP:\n",
    "\n",
    "* joined_lower for functions, methods, attributes\n",
    "* joined_lower or ALL_CAPS for constants\n",
    "* StudlyCaps for classes\n",
    "* camelCase only to conform to pre-existing conventions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Practice Defensive Programming\n",
    "\n",
    "Use `assert` to check internal correctness.\n",
    "\n",
    "*   The `assert` statement checks whether a condition is true.\n",
    "    *   \"This must be true here or something has gone wrong.\"\n",
    "*   Like `if`, but signals an error instead of controlling a block of code.\n",
    "*   By default, Python stops the program and displays the error,\n",
    "    along with a *traceback* of the call stack\n",
    "    to help you figure out what went wrong.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def calc_GDP(income, population):\n",
    "    assert population > 0 , 'Population cannot be 0 or negative'\n",
    "    return(income/population)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "calc_GDP(40000000, -2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Don't reinvent the wheel\n",
    "\n",
    "Before writing any code,\n",
    "\n",
    "* Check Python's standard library.\n",
    "\n",
    "* Check the Python Package Index (the \"Cheese Shop\"): http://cheeseshop.python.org/pypi\n",
    "\n",
    "* Search the web. Google is your friend."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Learn more:\n",
    "\n",
    "* \"Code like a Pythonist\" http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html)\n",
    "* \"Pep Styleguide\", https://www.python.org/dev/peps/pep-0008/)\n",
    "* \"Python Objects\", Fredrik Lundh, http://www.effbot.org/zone/python-objects.htm\n",
    "* \"Python track: python idioms\", http://www.cs.caltech.edu/courses/cs11/material/python/misc/python_idioms.html\n",
    "* \"Be Pythonic\", Shalabh Chaturvedi, http://www.cafepy.com/article/be_pythonic/ (PDF version)\n",
    "* \"Python Idioms\", http://www.gungfu.de/facts/wiki/Main/PythonIdioms\n",
    "* \"The Hitchhiker’s Guide to Python\", http://docs.python-guide.org/en/latest/\n",
    "* \"What is Pythonic?\", http://blog.startifact.com/posts/older/what-is-pythonic.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
